/*
 自定义Promise 
 */


 (function(window){


    const STATUS_PENDING = 'pending';
    const STATUS_RESOLVED = 'resolved'
    const STATUS_REJECT = 'rejected'

    function Promise(excutor){
        const self = this;
        self.status = STATUS_PENDING;
        self.data = undefined;
        self.callbacks = []; // {onResolved() {}, onRejected(){}}
        
        function resolve(value){
            if(self.status !== STATUS_PENDING){
                return;
            }

            self.status = STATUS_RESOLVED;
            self.data = value;
            
            if(self.callbacks.length > 0){
                self.callbacks.forEach(calbacksObj => {
                    setTimeout(() => {
                        calbacksObj.onResolved(value);
                    }, 0);
                });
            }

        }

        function reject(reason){
            if(self.status !== STATUS_PENDING){
                return;
            }

            self.status = STATUS_REJECT;
            self.data = reason;
            
            if(self.callbacks.length > 0){
                self.callbacks.forEach(calbacksObj => {
                    setTimeout(() => {
                        calbacksObj.onRejected(reason);
                    }, 0);
                });
            }
        }
        try{
            excutor(resolve, reject);
        } catch(error){
            reject(error);
        }

    }

    Promise.prototype.then = function(onResolved, onRejected){

        onRejected = typeof onRejected === 'function' ? onRejected : reason=>{throw reason}
        onResolved = typeof onResolved === 'function' ? onResolved : value => value
         
        const self = this;
        return new Promise((resolve, reject)=>{
            function handle(callback){
                try{
                    const result = callback(self.data);
                    if(result instanceof Promise){
                        // result.then(
                        //     value=>resolve(value),
                        //     reason => reject(reason)
                        // ); 
                        result.then(resolve, reject);
                    } else {
                        resolve(result);
                    }
                } catch (error){
                    reject(error);
                }
            }
            
            if(self.status === STATUS_PENDING){
                self.callbacks.push({
                    onResolved(value){
                        handle(onResolved)
                    },
                    onRejected(reason){
                        handle(onRejected)
                    }
                })
            } else if (self.status === STATUS_RESOLVED){
                setTimeout(() => {
                    handle(onResolved);

                }, 0);
            } else {
                setTimeout(() => {
                    handle(onRejected);
                }, 0);
            }
        });
    }

    Promise.prototype.catch = function(onReject){
        return this.then(undefined, onReject);
    }

    Promise.resolve = function(value){
         return new Promise((resolve, reject)=>{
            if(value instanceof Promise){
                value.then(resolve, reject);
            } else {
                resolve(value);
            }
         });
    }

    Promise.reject = function(reason){
        return new Promise((resolve, reject)=>{
            reject(reason);
        })
    }

    Promise.all = function(promises){
        const values = new Array(promises.length);
        let resolvedCount = 0;
        return new Promise((resolve, reject)=>{
            promises.forEach((p, index)=>{
                Promise.resolve(p).then(
                    value =>{
                        values[index] = value;
                        resolvedCount++;
                        if(resolvedCount == promises.length){
                            resolve(values);
                        }
                    },
                    reason => {
                        reject(reason);
                    }
                )
            });
        });
    }

    Promise.race = function(promises){

        return new Promise((resolve, reject)=>{
            promises.forEach((p)=>{
                Promise.resolve(p).then(
                    value =>{
                        resolve(value);
                    },
                    reason => {
                        reject(reason);
                    }
                )
            });
        });
    }


    Promise.resolveDelay = function(value, time){
        return new Promise((resolve, reject)=>{
            setTimeout(() => {
                if(value instanceof Promise){
                    value.then(resolve, reject);
                } else {
                    resolve(value);
                }                
            }, time);
         });
    }

    Promise.rejectDelay = function(value, time){
        return new Promise((resolve, reject)=>{
            setTimeout(() => {
                reject(value);
            }, time);
        })
    }

    window.Promise = Promise;
 })(window)